package com.cssw.fyzb.tps.third.tf56pay.sign;

import com.cssw.fyzb.tps.third.tf56pay.common.JsonResult;
import com.cssw.fyzb.tps.third.tf56pay.common.SignType;
import com.cssw.fyzb.tps.third.tf56pay.domain.dto.CertDTO;
import com.itrus.cryptorole.bc.RecipientBcImpl;
import com.itrus.cryptorole.bc.SenderBcImpl;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import static java.util.Comparator.reverseOrder;

public class ItrusRSA {

    private final static Logger logger = LoggerFactory.getLogger(ItrusRSA.class);
    /**
     * itrusRSASign
     */
    private static final String TF_SIGN_PARAM = "tf_sign";

    /**
     * 校验
     *
     * @param params  需要校验的参数
     * @param sign    签名
     * @return 校验结果
     */
    public static JsonResult verify(Map<String, Object> params, String sign) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setSignMsg(sign);
        jsonResult.setSignType(SignType.RSA.name());
        try {
            params.remove(TF_SIGN_PARAM);
            String oriData = sortMapByKey(params);
            jsonResult.setOrigMsg(oriData);
            RecipientBcImpl recipient = new RecipientBcImpl();
            //验签方法
            X509Certificate x509Certificate = recipient.verifySignature(oriData.getBytes(StandardCharsets.UTF_8), Base64.decodeBase64(sign));
            jsonResult.setResult(0);
            jsonResult.setSubjectDN(x509Certificate.getSubjectDN().getName());
        } catch (Exception e) {
            logger.warn("签名验证失败，原文已遭篡改。", e);
            jsonResult.setResult(-2);
            jsonResult.setMsg("签名验证失败，原文已遭篡改。");
        }
        return jsonResult;
    }



    /**
     * 加签
     *
     * @param paraMap 加签参数
     * @param certDTO 证书配置项
     * @return 签名
     */
    public static JsonResult sign(Map<String, Object> paraMap, CertDTO certDTO) {
        String oriData = sortMapByKey(paraMap);
        return sign(oriData,certDTO);
    }

    /**
     * 加签
     *
     * @param plaintext 明文
     * @param certDTO 证书配置项
     * @return 签名
     */
    public static JsonResult sign(String plaintext, CertDTO certDTO) {
        String sign = "";
        JsonResult jr;
        try {
            SenderBcImpl send = new SenderBcImpl();
            send.initCertWithKey(certDTO.getPfxFilePath(), certDTO.getPfxPassword());
            byte[] tsign = send.signMessage(plaintext.getBytes(StandardCharsets.UTF_8));
            sign = Base64.encodeBase64String(tsign);
            jr = new JsonResult("加签成功", 0, SignType.RSA.name(), plaintext, sign);
        } catch (Exception e) {
            logger.warn("系统加签异常", e);
            jr = new JsonResult("系统加签异常", -1, SignType.RSA.name(), "", "");
        }
        return jr;
    }

    private static String sortMapByKey(Map<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        map.keySet().removeIf(key -> null == map.get(key));
        Map<String, Object> sortedMap = new TreeMap<>(reverseOrder());
        sortedMap.putAll(map);
        StringBuilder result = new StringBuilder();
        for (Entry<String, Object> entry : sortedMap.entrySet()) {
            result.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        return result.toString();
    }

}
